home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / program / cpp112.zoo / src / pound.c < prev    next >
C/C++ Source or Header  |  1994-07-07  |  8KB  |  368 lines

  1.  
  2. /*---------------------------------------------------------------------*\
  3. |                                    |
  4. | CPP -- a stand-alone C preprocessor                    |
  5. | Copyright (c) 1993 Hacker Ltd.        Author: Scott Bigham    |
  6. |                                    |
  7. | Permission is granted to anyone to use this software for any purpose    |
  8. | on any computer system, and to redistribute it freely, with the    |
  9. | following restrictions:                        |
  10. | - No charge may be made other than reasonable charges for repro-    |
  11. |     duction.                                |
  12. | - Modified versions must be clearly marked as such.            |
  13. | - The author is not responsible for any harmful consequences of    |
  14. |     using this software, even if they result from defects therein.    |
  15. |                                    |
  16. | pound.c -- handle preprocessor directives                |
  17. \*---------------------------------------------------------------------*/
  18.  
  19. #include <stddef.h>
  20. #include <string.h>
  21. #include <stdlib.h>
  22. #include <errno.h>
  23. #include <ctype.h>
  24. #include "global.h"
  25.  
  26. #define IF_STACK_SIZE 10
  27. #define N_DIRS nelems(d_table)
  28. #define IF_STATE (if_sp[-1])
  29.  
  30. #define COND_FALSE    0
  31. #define COND_ELSE_SEEN    4
  32. #define COND_DONE_TRUE    8
  33.  
  34. #if 0
  35. /* a bundle of information about a preprocessor directive */
  36. typedef struct {
  37.   char *word;
  38.   int is_cond;
  39.   void (*handler) __PROTO((void));
  40. } Directive;
  41.  
  42. #endif
  43.  
  44. static int *if_stack, if_stack_size;
  45. int *if_sp;
  46.  
  47. extern void do_include __PROTO((void));
  48. extern void do_define __PROTO((void));
  49. extern void do_undefine __PROTO((void));
  50.  
  51. /* set up the conditional-compile stack */
  52. void cond_setup()
  53. {
  54.   if_sp = if_stack = (int *)mallok((if_stack_size = IF_STACK_SIZE) * sizeof (int));
  55.  
  56.   *if_sp++ = COND_TRUE;
  57. }
  58.  
  59. /*
  60.    endif_check() -- see if there are states left on the stack; each
  61.    corresponds to a missing #endif
  62. */
  63. void endif_check()
  64. {
  65.   int i;
  66.  
  67.   i = (int)(if_sp - if_stack) - 1;
  68.   if (i) {
  69.     while (i--)
  70.       error("missing #endif");
  71.   }
  72.   if_sp = if_stack;
  73.   *if_sp++ = COND_TRUE;
  74. }
  75.  
  76. /* cond_shutdown() -- free the conditional-compile stack() */
  77. void cond_shutdown()
  78. {
  79.   free(if_stack);
  80. }
  81.  
  82. /* cond_push() -- push a conditional-compile state onto the stack */
  83. static void cond_push(s)
  84.   int s;
  85. {
  86.   if (if_sp - if_stack >= if_stack_size) {
  87.     ptrdiff_t dp;
  88.  
  89.     dp = if_sp - if_stack;
  90.     if_stack = reallok(if_stack, (if_stack_size *= 2) * sizeof (int));
  91.  
  92.     if_sp = if_stack + dp;
  93.   }
  94.   *if_sp++ = s;
  95. }
  96.  
  97. /* cond_pop() -- remove a conditional-compile state from the stack */
  98. static void cond_pop()
  99. {
  100.   if (if_sp - if_stack <= 1)
  101.     error("unmatched #endif");
  102.   else
  103.     if_sp--;
  104. }
  105.  
  106. /* do_if() -- handle an #if directive */
  107. static void do_if()
  108. {
  109.   cond_push(!cond_true()? COND_NESTED :
  110.         if_expr()? COND_TRUE | COND_DONE_TRUE :
  111.         COND_FALSE
  112.   );
  113. }
  114.  
  115. /* do_ifdef() -- handle an #ifdef directive */
  116. static void do_ifdef()
  117. {
  118.   TokenP T;
  119.  
  120.   T = _one_token();
  121.   if (T->type != ID)
  122.     error("argument \"%s\" to #ifdef is not an identifier", token_txt(T));
  123.   else {
  124.     cond_push(!cond_true()? COND_NESTED :
  125.           lookup(token_txt(T), T->hashval) ? COND_TRUE | COND_DONE_TRUE :
  126.           COND_FALSE
  127.     );
  128.   }
  129.   free_token(T);
  130.   T = _one_token();
  131.   if (T->type != EOL)
  132.     warning("garbage after #ifdef");
  133.   free_token(T);
  134. }
  135.  
  136. /* do_ifndef() -- handle an #ifndef directive */
  137. static void do_ifndef()
  138. {
  139.   TokenP T;
  140.  
  141.   T = _one_token();
  142.   if (T->type != ID)
  143.     error("argument \"%s\" to #ifndef is not an identifier", token_txt(T));
  144.   else {
  145.     cond_push(!cond_true()? COND_NESTED :
  146.           lookup(token_txt(T), T->hashval) ? COND_FALSE :
  147.           COND_TRUE | COND_DONE_TRUE
  148.     );
  149.   }
  150.   free_token(T);
  151.   T = _one_token();
  152.   if (T->type != EOL)
  153.     warning("garbage after #ifndef");
  154.   free_token(T);
  155. }
  156.  
  157. /* do_else() -- handle an #else directive */
  158. static void do_else()
  159. {
  160.   TokenP T;
  161.  
  162.   if (IF_STATE & COND_ELSE_SEEN)
  163.     error("#else after #else");
  164.   if (IF_STATE & COND_DONE_TRUE)
  165.     IF_STATE &= (~COND_TRUE);
  166.   else
  167.     IF_STATE |= (COND_TRUE | COND_DONE_TRUE);
  168.   T = _one_token();
  169.   if (T->type != EOL)
  170.     warning("garbage after #else");
  171.   free_token(T);
  172. }
  173.  
  174. /* do_elif() -- handle an #elif directive */
  175. static void do_elif()
  176. {
  177.   TokenP T;
  178.  
  179.   if (IF_STATE & COND_ELSE_SEEN)
  180.     error("#elif after #else");
  181.   if (IF_STATE & COND_DONE_TRUE)
  182.     IF_STATE &= (~COND_TRUE);
  183.   else if (if_expr())
  184.     IF_STATE |= (COND_TRUE | COND_DONE_TRUE);
  185.   else
  186.     IF_STATE &= (~COND_TRUE);
  187. }
  188.  
  189. /* do_endif() -- handle an #endif directive */
  190. static void do_endif()
  191. {
  192.   TokenP T;
  193.  
  194.   cond_pop();
  195.   T = _one_token();
  196.   if (T->type != EOL)
  197.     warning("garbage after #endif");
  198.   free_token(T);
  199. }
  200.  
  201. /* do_line() -- handle a #line directive */
  202. static void do_line()
  203. {
  204.   unsigned long ln;
  205.   TokenP Tn, Tf;
  206.   int l;
  207.  
  208.   _tokenize_line();
  209.   Tn = exp_token();
  210.   if (Tn->type != NUMBER) {
  211.     error("malformed number \"%s\" in #line directive", token_txt(Tn));
  212.     free_token(Tn);
  213.     return;
  214.   }
  215.   Tf = exp_token();
  216.   if (Tf->type != STR_CON && Tf->type != EOL) {
  217.     error("malformed filename \"%s\" in #line directive", token_txt(Tf));
  218.     free_token(Tn);
  219.     free_token(Tf);
  220.     return;
  221.   }
  222.   if (Tf->type == STR_CON) {
  223.     l = strlen(token_txt(Tf)) - 2;
  224.     free(cur_file);
  225.     cur_file = mallok(l + 1);
  226.     strncpy(cur_file, token_txt(Tf) + 1, l);
  227.     cur_file[l] = '\0';
  228.     free_token(Tf);
  229.     Tf = exp_token();
  230.     if (Tf->type != EOL)
  231.       error("garbage after #line");
  232.     free_token(Tf);
  233.   }
  234.   this_line = next_line = Tn->val;
  235.   sync_line(0);
  236.   free_token(Tn);
  237. }
  238.  
  239. /* do_error() -- handle an #error directive */
  240. static void do_error()
  241. {
  242.   error("%s", rest_of_line());
  243. }
  244.  
  245. /* write_pragma_text() -- write a token contaning the text |s| directly
  246.    to the output file
  247. */
  248. static void write_pragma_text(s)
  249.   const char *s;
  250. {
  251.   register TokenP T = mk_printable(s);
  252.  
  253.   print_token(T);
  254.   free_token(T);
  255. }
  256.  
  257. /* do_pragma() -- handle a #pragma directive */
  258. static void do_pragma()
  259. {
  260.   TokenP T = _one_token();
  261.  
  262.   if (T->type == EOL) {
  263.     warning("empty #pragma directive");
  264.     free_token(T);
  265.     return;
  266.   }
  267.   if (in_config_file) {
  268.     /* pragmas that are enabled only in config file */
  269.     if (streq(token_txt(T), "CPP_cmdline_arg")) {
  270.       char *s = rest_of_line();
  271.  
  272.       while (isspace(*s))
  273.     s++;
  274.       if (*s == '-')
  275.     do_cmdline_arg(s);
  276.       else
  277.     error("invalid cmdline arg \"%s\" in #pragma CPP_cmdline_arg", s);
  278.     } else if (streq(token_txt(T), "CPP_delayed")) {
  279.       if (Argc_end != 0)
  280.     error("#pragma CPP_delayed cannot be repeated");
  281.       else
  282.     do_all_cmdline_args();
  283.     }
  284.   }
  285.   if (fluff_mode && streq(token_txt(T), "fluff")) {
  286.     /* pragmas for use with fluff */
  287.     TokenP T0 = _one_token();
  288.  
  289.     if (T0->type == EOL) {
  290.       error("empty `#pragma fluff' directive");
  291.     } else if (streq(token_txt(T0), "varargs")) {
  292.       write_pragma_text("__FLUFF_varargs");
  293.       write_pragma_text("\n");
  294.       last_line++;
  295.     } else {
  296.       error("invalid `#pragma fluff directive \"%s\"", token_txt(T0));
  297.     }
  298.     free_token(T0);
  299.   }
  300.   free_token(T);
  301.   return;
  302. }
  303.  
  304. /*
  305.    directive() -- perform the directive on the current input line
  306. */
  307. void directive()
  308. {
  309.   TokenP T;
  310.   int i;
  311.  
  312.   T = _one_token();
  313.   if (T->type == EOL) {
  314.     free_token(T);
  315.     return;
  316.   }
  317.   switch (T->hashval + token_txt(T)[0]) {
  318.   case 782:            /* #define */
  319.     if (cond_true())
  320.       do_define();
  321.     break;
  322.   case 200:            /* #undef */
  323.     if (cond_true())
  324.       do_undefine();
  325.     break;
  326.   case 713:            /* #include */
  327.     if (cond_true())
  328.       do_include();
  329.     break;
  330.   case 645:            /* #if */
  331.     do_if();
  332.     break;
  333.   case 362:            /* #ifdef */
  334.     do_ifdef();
  335.     break;
  336.   case 1032:            /* #ifndef */
  337.     do_ifndef();
  338.     break;
  339.   case 559:            /* #else */
  340.     do_else();
  341.     break;
  342.   case 230:            /* #elif */
  343.     do_elif();
  344.     break;
  345.   case 750:            /* #endif */
  346.     do_endif();
  347.     break;
  348.   case 675:            /* #line */
  349.     if (cond_true())
  350.       do_line();
  351.     break;
  352.   case 679:            /* #error */
  353.     if (cond_true())
  354.       do_error();
  355.     break;
  356.   case 1039:            /* #pragma */
  357.     if (cond_true())
  358.